#!/usr/bin/env python
#
#       caselogic.py
#
#       Copyright 2009 karthikeyan S. <kaarthikeyapreyan@gmail.com>
#
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import os
import sys

from types import BooleanType,FloatType,StringType,IntType

import handleargs

class ArgLogic:

    def noArg(self,warg,name,mod=None,classmod=None,clargs=None):
        """
        Write Logic for entity without any argument
        """
        warg.writecases(mod.__name__,name,0,'Pass',\
            comment="With_Only_Valid_Arguments",\
            classmod=classmod,clargs=clargs)
        warg.writecases(mod.__name__,name,1,'Fail',["'TestStr0'"],\
            comment="With_Arg",classmod=classmod,clargs=clargs)

    def _prediction(self,name,Args=(),mod=None,classmod=None,clargs=None):
        """
        Name : Entity under discussion
        Args : Arginfo
        classmod : Module name incase if its a method
                   None for other entities
        mod : Class attribute for method entities
              Module attribute for other entities
        """
        genargs=[]
        deftemp=[]
        myargs=[]
        argnum=len(Args[0])
        defaultvals=handleargs.Args().formatargs(Args)

        if argnum - len(defaultvals):
            for predicted in self.generatePrediction(argnum - len(defaultvals)):
                genargs.extend(predicted)
                genargs.extend(map(lambda x : x[1],defaultvals))
                deftemp.append(genargs)
                genargs=[]

            for predicted in deftemp:
                myargs=self.testPrediction\
                    (name,predicted,mod=mod,checkclass=classmod,clargs=clargs)
                if not myargs== None:
                    break
        else :
            genargs.extend(self.generatePrediction(argnum))
            for predicted in genargs:
                myargs=self.testPrediction\
                    (name,predicted,mod=mod,checkclass=classmod,clargs=clargs)
                if not myargs == None:
                    break

        return (myargs,defaultvals,predicted)

    def WhArg(self,warg,name,Args=(),mod=None,classmod=None,clargs=None):
        """
        Write Logic for entity with argument
        """
        myargs,defaultvals,predicted=self._prediction(name,Args,mod,classmod,clargs)
        argnum=len(Args[0])
        
        if not myargs== None :
            if argnum - len(defaultvals) :
                warg.writecases(mod.__name__,name,0,'Fail',\
                    comment="Without_Arg",classmod=classmod,clargs=clargs) # Lower Boundary Arguments
            warg.writecases(mod.__name__,name,argnum - len(defaultvals),'Pass',\
                arguments=myargs[:argnum - len(defaultvals)],\
                comment="With_Only_Valid_Arguments",\
                classmod=classmod,clargs=clargs) # With only Arguments

            if len(defaultvals) :
                warg.writecases(mod.__name__,name,argnum,'Pass',\
                    arguments=myargs,comment="With_Valid_Args_And_Kwargs",\
                    classmod=classmod,clargs=clargs) # With Arguments and Keywords
            warg.writecases(mod.__name__,name,argnum,'Fail',\
                arguments=self.switch(predicted,SNumArgs=1),\
                comment="With_OneInvalid_Arg",classmod=classmod,clargs=clargs)

            if argnum >= 2:
                warg.writecases(mod.__name__,name,argnum,'Fail',\
                    arguments=self.switch(predicted,SNumArgs=2),\
                    comment="With_TwoInvalid_Args",classmod=classmod,clargs=clargs)

            if defaultvals :
                warg.writecases(mod.__name__,name,argnum,'Fail',\
                    arguments=self.switch(predicted,ind=argnum-1),\
                    comment="With_Invalid_Kwargs",classmod=classmod,clargs=clargs)

            myargs.append("'TestStr2'")
            warg.writecases(mod.__name__,name,argnum+1,'Fail',\
            arguments=myargs,comment="With_Args_Than_Specified",\
            classmod=classmod,clargs=clargs) # Upper Boundary Arguments

    def generatePrediction(self,numarg):
        """
        Predict the type of the argument
        """
        determined=[]
        temp=['TestStr',False,96]
        basetype=[[5,"TestStr",True]]
        while numarg > len(basetype) :
            basetype.append(temp)

        for i in self.combinations(basetype):
            determined.append(i)

        return determined

    def combinations(self,lol, parent=[], chld=[]):
        """
        Generator that yields all possible combinations from a list of lists.
        """
        if parent == []:
            parent = lol[0]
            templ = lol[1:]
        else:
            templ = lol
        for item in parent:
            if len(templ) > 0:
                for c in self.combinations(templ[1:], templ[0], chld+[item]):
                    yield c
            else:
                yield chld+[item]

    def testPrediction\
        (self,entity,predictedlist,mod=None,checkclass=None,clargs=None):
        """
        Check if the generated predictions are valid
        """
        flg=0
        tempredict=[]
        tempredict.extend(predictedlist)
        for index,val in enumerate(tempredict) :
            if type(val) == (StringType):
                tempredict[index]="'%s'"%val
            if type(val) in (BooleanType,FloatType,IntType):
                tempredict[index] = str(val)

        sys_stdout= open("PyTestTemp.log", "a")
        original_stdout = sys.stdout
        sys.stdout = sys_stdout
        if checkclass and not clargs:
            try:
                exec("mod().%s(%s)"%(entity,",".join(tempredict)))
                flg=1
            except Exception, E :
                flg=0
        elif checkclass and clargs:
            try:
                exec("mod(%s).%s(%s)"\
                    %(",".join(clargs),entity,",".join(tempredict)))
                flg=1
            except Exception, E :
                flg=0
        else :
            try:
                exec("mod.%s(%s)"%(entity,",".join(tempredict)))
                flg=1
            except Exception, E :
                flg=0

        sys.stdout = original_stdout
        sys_stdout.close()

        os.unlink('PyTestTemp.log')
        if flg == 1:
            return tempredict
        else :
            return None


    def switch(self,glist,SNumArgs=None,ind=None) :
        """
        Switch the specified number of entities in the given list
        With Invalid alternates
        """
        modlist=[]
        modlist.extend(glist)

        if not ind:
            for index,entity in enumerate(glist) :
                if index < SNumArgs :
                    if type(entity) in (IntType,BooleanType):
                        modlist[index]="'TestStr4'"
                    elif type(entity) == StringType:
                        modlist[index]= '20.11'
                else :
                    if type(entity) in (IntType,BooleanType):
                        modlist[index]=str(entity)
                    elif type(entity) == StringType :
                        modlist[index]= "'%s'"%entity
        else :
            for sindex,sentity in enumerate(glist):
                if sindex == ind :
                    if type(modlist[sindex]) in (IntType,BooleanType):
                        modlist[sindex]="'TestStr5'"
                    elif type(modlist[sindex]) == StringType:
                        modlist[sindex]= '0.15'
                else :
                    if type(sentity) in (IntType,BooleanType):
                        modlist[sindex]=str(sentity)
                    elif type(sentity) == StringType:
                        modlist[sindex]= "'%s'"%sentity

        return modlist
